﻿using System;
using CommonLibrary.Models.ControllerStates;
using CommonLibrary.Models.ControllerStates.PS3;
using ConnectionManager.Extensions;

namespace ConnectionManager.ConnectionProcesors.PS3
{
    /// <summary>
    /// Killzone has an issue with the inputs, especially the stick inputs can get "Stuck" for some unknown reason
    /// It seems to check if a value has changed from the prev val and if not the input is not updated to the prev value? wtf? duno ...
    /// This creates an issue if, say the joistick is at a value then instantly back to null
    /// If the null value is not changed and the game is "stuck" on the last value the input will be "stuck"
    /// 
    /// Solution: Always send a random value on each update within the null zone
    /// </summary>
    class Killzone3Procesor : IConnectionProcesor
    {
        private static ushort _rAxisX;
        private static ushort _rAxisY;

        private static int _countx;
        private static int _county;
        private const int SentTimes = 5;

        private static readonly Random Random = new Random();

        public void Process(ControllerState controllerState)
        {
            PrecheckMoveAxis(controllerState as PS3ControllerState);
            PrecheckCursor(controllerState as PS3ControllerState);
        }

        public string GetName()
        {
            return "Killzone 3";
        }

        private void PrecheckMoveAxis(PS3ControllerState dataStructure)
        {
            // Fudge factor for movement keys
            if (dataStructure.User.LAxisX.NotCloseToMax())
                dataStructure.User.LAxisX = (ushort)(dataStructure.User.LAxisX + Random.Next(-20, 20));

            if (dataStructure.User.LAxisY.NotCloseToMax())
                dataStructure.User.LAxisY = (ushort)(dataStructure.User.LAxisY + Random.Next(-20, 20));
        }

        private static void PrecheckCursor(PS3ControllerState dataStructure)
        {
            if (dataStructure.User.RAxisX == _rAxisX && dataStructure.User.RAxisX.NotCloseToMax())
            {
                _countx++;
            }
            else
            {
                _rAxisX = dataStructure.User.RAxisX;
                _countx = 0;
            }

            if (dataStructure.User.RAxisY == _rAxisY && dataStructure.User.RAxisY.NotCloseToMax())
            {
                _county++;
            }
            else
            {
                _rAxisY = dataStructure.User.RAxisY;
                _county = 0;
            }

            if (_countx >= SentTimes)
            {
                dataStructure.User.RAxisX = // this version has the "stick return" effect added
                    (ushort)((ushort.MaxValue / 2 +
                    Math.Sign(dataStructure.User.RAxisX) * Math.Abs((ushort.MaxValue / 2) - Math.Abs(dataStructure.User.RAxisX)) * 0.7) +  // decay of the value
                    Random.Next(-50, 50)); // fudge factor to fix key "stick" in Killzone 3

                _rAxisX = dataStructure.User.RAxisX;
            }

            if (_county >= SentTimes)
            {
                dataStructure.User.RAxisY =
                    (ushort)((ushort.MaxValue / 2 +
                    Math.Sign(dataStructure.User.RAxisY) * Math.Abs((ushort.MaxValue / 2) - Math.Abs(dataStructure.User.RAxisY)) * 0.7) +
                    Random.Next(-50, 50));

                _rAxisY = dataStructure.User.RAxisY;
            }
        }
    }
}
